package cn.edu.stu.syllabus.login;

import android.annotation.SuppressLint;
import android.graphics.Bitmap;
import android.os.Build;
import android.os.Bundle;
import android.support.annotation.RequiresApi;
import android.support.design.widget.CoordinatorLayout;
import android.support.v4.content.ContextCompat;
import android.support.v7.widget.Toolbar;
import android.text.TextUtils;
import android.util.Log;
import android.view.MenuItem;
import android.webkit.CookieManager;
import android.webkit.JavascriptInterface;
import android.webkit.WebResourceRequest;
import android.webkit.WebSettings;
import android.webkit.WebView;
import android.webkit.WebViewClient;
import android.widget.FrameLayout;

import com.facebook.stetho.common.LogUtil;

import java.util.concurrent.TimeUnit;

import javax.inject.Inject;

import butterknife.BindView;
import cn.edu.stu.syllabus.R;
import cn.edu.stu.syllabus.base.BaseActivity;
import cn.edu.stu.syllabus.switcher.DayNightSwitcher;
import cn.edu.stu.syllabus.utils.ActivityUtils;
import cn.edu.stu.syllabus.utils.NetworkUtils;
import rx.Observable;
import rx.Subscription;
import rx.android.schedulers.AndroidSchedulers;
import rx.functions.Action0;
import rx.functions.Action1;

public class LoginActivity extends BaseActivity implements Toolbar.OnMenuItemClickListener,
        LoginCallBack, LoginListener {

    @BindView(R.id.contentFrame)
    FrameLayout mContentFrame;
    @BindView(R.id.loginWebView)
    WebView mLoginWebView;

    private Subscription mTimeOutSubscription;

    private Subscription mShowSourceSubscription;

    private LoginCallBack mLoginCallBack;

    private LoginWebViewClient mLoginClient;

    private String mUsername;

    private String mPassword;

    @Inject
    LoginPresenter mLoginPresenter;

    public static final int TIME_OUT = 15 * 1000;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
    }

    @Override
    protected int getContentViewId() {
        return R.layout.activity_login;
    }

    @Override
    protected void init(Bundle savedInstanceState) {

        mToolbar.setNavigationIcon(ContextCompat.getDrawable(this, R.drawable.ic_close));
        mToolbar.inflateMenu(R.menu.menu_login);
        mToolbar.setOnMenuItemClickListener(this);

        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
            int statusHeight = getStatusBarHeight();
            CoordinatorLayout.LayoutParams contentFrameLayoutParams = (CoordinatorLayout.LayoutParams) mContentFrame.getLayoutParams();
            contentFrameLayoutParams.setMargins(0, contentFrameLayoutParams.topMargin + statusHeight, 0, 0);
        }

        initWebView();

        LoginFragment loginFragment = (LoginFragment) getSupportFragmentManager()
                .findFragmentById(R.id.contentFrame);

        if (loginFragment == null) {
            loginFragment = LoginFragment.newInstance();
            ActivityUtils.addFragmentToActivity(getSupportFragmentManager(),
                    loginFragment, R.id.contentFrame);
        }
        mLoginCallBack = loginFragment;

        DaggerLoginComponent.builder()
                .loginPresenterModule(new LoginPresenterModule(loginFragment))
                .build().inject(this);
    }

    @SuppressLint({"AddJavascriptInterface", "SetJavaScriptEnabled"})
    private void initWebView() {
        mLoginClient = new LoginWebViewClient();
        mLoginWebView.setWebViewClient(mLoginClient);
        mLoginWebView.addJavascriptInterface(new InJavaScriptLocalObj(), "local_obj");

        WebSettings settings = mLoginWebView.getSettings();
        settings.setJavaScriptEnabled(true);
        settings.setCacheMode(WebSettings.LOAD_NO_CACHE);
    }


    @Override
    public boolean onMenuItemClick(MenuItem item) {
        int id = item.getItemId();
        if (id == R.id.action_dayNight) {
            DayNightSwitcher.getInstance().switchActMode(this);
        }
        return true;
    }

    @Override
    public void onCodeGetSuccess(String code) {
        LogUtil.e("onCodeGetSuccess: " + code);
        mLoginCallBack.onCodeGetSuccess(code);
        stopLogin();
    }

    @Override
    public void onCodeGetFail() {
        LogUtil.e("onCodeGetFail");
        mLoginCallBack.onCodeGetFail();
        stopLogin();
    }

    @Override
    public void onTimeOut() {
        LogUtil.e("onTimeOut");
        mLoginCallBack.onTimeOut();
        stopLogin();
    }

    @Override
    public void onUnknowHost(String url) {
        LogUtil.e("onUnknowHost: " + url);
        mLoginCallBack.onUnknowHost(url);
        stopLogin();
    }

    @Override
    public void onPostMany() {
        LogUtil.e("onPostMany");
        mLoginCallBack.onPostMany();
        stopLogin();
    }

    @Override
    public void onUnconnect() {
        LogUtil.e("onUnconnect");
        mLoginCallBack.onUnconnect();
    }

    @Override
    public void onLogin(String username, String password) {
        if (NetworkUtils.isNetworkConnected(this)) {
            mUsername = username;
            mPassword = password;
            startLogin();
        } else {
            onUnconnect();
        }
    }

    private void startLogin() {
        mLoginClient.clearCode();
        mLoginWebView.clearCache(true);
        CookieManager.getInstance().removeAllCookie();

        mTimeOutSubscription = Observable.just(null)
                .delay(TIME_OUT, TimeUnit.MILLISECONDS)
                .observeOn(AndroidSchedulers.mainThread())
                .subscribe(new Action1<Object>() {
                    @Override
                    public void call(Object o) {
                        onTimeOut();
                    }
                });

        mLoginWebView.loadUrl("about:blank");
        mLoginWebView.loadUrl("https://oauth.stu.edu.cn/oauth2/authorize?response_type=code&client_id=stusyllabus&redirect_uri=http://119.29.95.245:8080/oauth2_android");
    }

    private void stopLogin() {
        mLoginWebView.stopLoading();
        if (mTimeOutSubscription != null && !mTimeOutSubscription.isUnsubscribed()) {
            mTimeOutSubscription.unsubscribe();
        }
        if (mShowSourceSubscription != null && !mShowSourceSubscription.isUnsubscribed()) {
            mShowSourceSubscription.unsubscribe();
        }
    }

    @Override
    protected void onDestroy() {
        stopLogin();
        super.onDestroy();
    }

    private final class LoginWebViewClient extends WebViewClient {

        private boolean isGetCode;

        public void clearCode() {
            isGetCode = false;
        }

        @RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)
        @Override
        public boolean shouldOverrideUrlLoading(WebView view, WebResourceRequest request) {
            view.loadUrl(request.getUrl().toString());
            return true;
        }

        @Override
        public boolean shouldOverrideUrlLoading(WebView view, String url) {
            view.loadUrl(url);
            return true;
        }

        @Override
        public void onPageStarted(WebView view, String url, Bitmap favicon) {
            super.onPageStarted(view, url, favicon);
        }

        public void onPageCommitVisible(WebView view, String url) {
            super.onPageCommitVisible(view, url);
        }

        @Override
        public void onPageFinished(final WebView view, String url) {
            LogUtil.e("url:" + url);
            if (url.equals("about:blank")) {
                return;

            } else if (url.endsWith("oauth.stu.edu.cn/cas")
                    || url.startsWith("https://oauth.stu.edu.cn/cas?ticket=")
                    || url.startsWith("http://oauth.stu.edu.cn/oauth2/authorize")) {
                return;

            } else if (url.equals("https://sso.stu.edu.cn/login?mobile=true&service=https%3A%2F%2Foauth.stu.edu.cn%2Fcas")) {
                view.loadUrl("javascript:window.local_obj.showSource('<head>'+document.getElementsByTagName('html')[0].innerHTML+'</head>','false','true');void(0);");

            } else if (url.equals("https://oauth.stu.edu.cn/oauth2/authorize?response_type=code&client_id=stusyllabus&redirect_uri=http://119.29.95.245:8080/oauth2_android")) {
                Log.d("HTML", "get token");
                view.loadUrl("javascript:document.getElementById('user_oauth_approval').click();void(0);");

            } else if (url.startsWith("https://sso.stu.edu.cn/login;jsessionid=")) {
                view.loadUrl("javascript:window.local_obj.showSource('<head>'+document.getElementsByTagName('html')[0].innerHTML+'</head>','true','false');void(0);");

            } else if (url.startsWith("stu://syllabus:80/login?code=")) {
                String code = url.substring("stu://syllabus:80/login?code=".length(), url.length());
                if (!TextUtils.isEmpty(code)) {
                    if (!isGetCode) {
                        isGetCode = true;
                        if (mLoginCallBack != null) {
                            onCodeGetSuccess(code);
                        }
                    }
                }
            } else if (url.startsWith("http://119.29.95.245:8080/oauth2_android?code=")) {
                String code = url.substring("http://119.29.95.245:8080/oauth2_android?code=".length(), url.length());
                if (!TextUtils.isEmpty(code)) {
                    if (!isGetCode) {
                        isGetCode = true;
                        if (mLoginCallBack != null) {
                            onCodeGetSuccess(code);
                        }
                    }
                }
            } else {
                onUnknowHost(url);
            }
            super.onPageFinished(view, url);
        }
    }

    private final class InJavaScriptLocalObj {

        @JavascriptInterface
        public void showSource(final String html, final String isHandlerError, final String isHandlerLogin) {
            LogUtil.e("showSource");
            mShowSourceSubscription = AndroidSchedulers.mainThread()
                    .createWorker()
                    .schedule(new Action0() {
                        @Override
                        public void call() {
                            if (html.contains("login_notice")) {
                                onPostMany();
                            } else if (isHandlerError.equals("true") && html.contains("login_error")) {
                                onCodeGetFail();
                            } else if (isHandlerLogin.equals("true")) {
                                mLoginWebView.loadUrl(
                                        "javascript:document.getElementById(\"username\").value=\""
                                                + mUsername + "\";void(0);");
                                mLoginWebView.loadUrl(
                                        "javascript:document.getElementById(\"password\").value=\""
                                                + mPassword + "\";void(0);");
                                mLoginWebView.loadUrl(
                                        "javascript:document.getElementById('login').click();void(0);");
                            }
                        }
                    });
        }
    }
}
